<?php

namespace app\common\library\xmwechat\miniprogram;

use app\common\library\xmwechat\SingletonTrait;
use app\common\library\xmwechat\WechatService;
use EasyWeChat\MiniApp\Application;
use Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface;
use Symfony\Contracts\HttpClient\Exception\DecodingExceptionInterface;
use Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface;
use Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface;
use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface;

/**
 * 小程序服务
 */
class MpService extends WechatService
{
    protected ?Application $app = null;
    protected string $accessToken;

    use SingletonTrait;

    public function __construct()
    {
        parent::__construct();
        if (empty($this->miniProgramConfig['app_id']) || empty($this->miniProgramConfig['secret'])) {
            $this->result('请配置小程序appid或secret');
        }
        $this->app         = new Application([
            'app_id' => $this->miniProgramConfig['app_id'],
            'secret' => $this->miniProgramConfig['secret'],
        ]);
        $accessToken       = $this->app->getAccessToken();
        $this->accessToken = $accessToken->getToken();
    }

    /**
     * @param $params
     * @return array
     * @throws ClientExceptionInterface
     * @throws DecodingExceptionInterface
     * @throws RedirectionExceptionInterface
     * @throws ServerExceptionInterface
     * @throws TransportExceptionInterface
     * @throws \Exception
     * @author jsjxsz <QQ:1365962177>
     */
    public function getOpenidAndUnionid($params): array
    {
        try {
            $utils = $this->app->getUtils();
            // code需前端获取 传给api
            $wxData = $utils->codeToSession($params['code']);
            $openid = $wxData['openid'];
            // 小程序若未绑定微信开放平台（不是公众号），将获取不到unionid
            isset($wxData['unionid']) && !empty($wxData['unionid']) ? $unionid = $wxData['unionid'] : $unionid = '';
            return [
                'openid'  => $openid,
                'unionid' => $unionid
            ];
        } catch (\Exception $e) {
            $this->result($e->getMessage());
        }
    }

    /**
     * @param $params
     * @return array
     * @throws ClientExceptionInterface
     * @throws DecodingExceptionInterface
     * @throws RedirectionExceptionInterface
     * @throws ServerExceptionInterface
     * @throws TransportExceptionInterface
     * @throws \Exception
     * @author jsjxsz <QQ:1365962177>
     */
    public function getPhoneNumber($params): array
    {
        try {
            // code需前端获取 传给api
            $result = $this->app->getClient()->postJson('/wxa/business/getuserphonenumber?access_token=' . $this->accessToken, [
                'code' => (string)$params['code'],
            ]);
            $result = $result->toArray();
            if ($result['errcode'] == 0 && $result['errmsg'] == 'ok') {
                return $result;
            }
        } catch (\Exception $e) {
            $this->result($e->getMessage());
        }
        return [];
    }

    /**
     * 微信文本安全内容检测 单个appid调用上限为2000次/分钟，1,000,000次/天
     * scene 场景枚举值（1 资料；2 评论；3 论坛；4 社交日志）
     * @param array $params
     * @return bool
     * @throws ClientExceptionInterface
     * @throws DecodingExceptionInterface
     * @throws RedirectionExceptionInterface
     * @throws ServerExceptionInterface
     * @throws TransportExceptionInterface
     * @throws \Exception
     * @author jsjxsz <QQ:1365962177>
     */
    public function checkText(array $params): bool
    {
        try {
            isset($params['scene']) && !empty($params['scene']) ? $scene = $params['scene'] : $scene = 3;
            $api      = $this->app->getClient();
            $response = $api->postJson('/wxa/msg_sec_check?access_token=' . $this->accessToken, [
                "content" => utf8_encode($params['content']),
                "version" => 2, // 接口版本号，2.0版本为固定值2
                "scene"   => $scene,
                "openid"  => $params['openid']
            ]);
            $result   = $response->toArray();
            if (isset($result['result']['label']) && $result['result']['label'] == 100) {
                // 具体查看 https://developers.weixin.qq.com/miniprogram/dev/OpenApiDoc/sec-center/sec-check/msgSecCheck.html
                return true;
            }
        } catch (\Exception $exception) {
            $this->result($exception->getMessage());
        }
        return false;
    }

    /**
     * 检查音频、图片
     * 频率限制：单个 appId 调用上限为 2000 次/分钟，200,000 次/天；文件大小限制：单个文件大小不超过10M
     * @param $params
     * @return bool|array
     * @throws ClientExceptionInterface
     * @throws DecodingExceptionInterface
     * @throws RedirectionExceptionInterface
     * @throws ServerExceptionInterface
     * @throws TransportExceptionInterface
     * @throws \Exception
     * @author jsjxsz <QQ:1365962177>
     */
    public function checkMedia($params): bool|array
    {
        try {
            isset($params['media_type']) && !empty($params['media_type']) ? $media_type = $params['media_type'] : $media_type = 2;
            isset($params['scene']) && !empty($params['scene']) ? $scene = $params['scene'] : $scene = 3;
            $media_url = $params['media_url'];
            $api       = $this->app->getClient();
            $response  = $api->postJson('/wxa/media_check_async?access_token=' . $this->accessToken, [
                "media_url"  => $media_url,
                "media_type" => $media_type,
                "version"    => 2, // 接口版本号，2.0版本为固定值2
                "scene"      => $scene,
                "openid"     => $params['openid']
            ]);
            $result    = $response->toArray();
            if (isset($result['trace_id']) && !empty($result['trace_id'])) {
                // 请求成功
                // 检测结果需要异步推送（需先配置微信小程序消息推送相关参数）
                // trace_id	唯一请求标识，标记单次请求，用于匹配异步推送结果
                // 具体查看 https://developers.weixin.qq.com/miniprogram/dev/OpenApiDoc/sec-center/sec-check/mediaCheckAsync.html
                return $result;
            }
        } catch (\Exception $exception) {
            $this->result($exception->getMessage());
        }
        return false;
    }

    /**
     * @param array $params
     * @return bool
     * @author jsjxsz <QQ:1365962177>
     */
    public function checkSignature(array $params): bool
    {
        $server_token = $this->miniProgramConfig['server_token'];
        $tmpArr       = array($server_token, $params['timestamp'], $params['nonce']);
        sort($tmpArr, SORT_STRING);
        $tmpStr = implode($tmpArr);
        $tmpStr = sha1($tmpStr);
        if ($tmpStr == $params['signature']) {
            return true;
        } else {
            return false;
        }
    }

}